<template>
  <div class="page page-screenshare-image">
    <h4 class="text-center">选择要共享的窗口（Image方案）</h4>
    <form class="page-body row">
      <div class="col-4">
        <fieldset>
          <legend>窗口列表&操作</legend>
          <div class="fieldset-content">
            <div class="form-group screens-list">
              <div v-for="(v,i) in screensList" :key="i"
                :class="['screen-item', {active: i === screenActiveIndex}]"
                @click="screenItemClick(i)"
              >
                <img :src="v.thumbnail.toDataURL()">
              </div>
            </div>
            <div class="form-group">
              <x-button block @click="createSubWindow">创建子窗口监听数据流</x-button>
              <x-button block @click="sendStream">开始推流</x-button>
              <x-button block @click="stopStream">停止推流</x-button>
            </div>
          </div>
        </fieldset>
      </div>
      <div class="col-8">
        <fieldset>
          <legend>直播画面</legend>
          <div class="fieldset-content">
            <img :src="imgSrc" >
          </div>
        </fieldset>
      </div>
    </form>
  </div>
</template>

<script>
import io from 'socket.io-client'
const {ipcRenderer} = global.require('electron')

export default {
  name: 'page-screenshare-image',
  data () {
    return {
      wsWaiter: null,
      wsTimer: null,
      screensList: [],
      screenActiveIndex: -1,
      imgSrc: ''
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.getScreensList()
      this.startWebrtcServer()
      this.listenWebsocket()
    })
  },
  beforeDestroy () {
    this.closeWebrtcServer()
  },
  methods: {
    // 获取窗口列表
    getScreensList () {
      window.electron.desktopCapturer.getSources({types: ['window', 'screen']})
      .then((sources) => {
        this.screensList = sources || []
      })
    },
    // 获取指定窗口的镜像流数据
    getStreamBySource (source) {
      return navigator.mediaDevices.getUserMedia({
        audio: false,
        video: {
          mandatory: {
            chromeMediaSource: 'desktop',
            chromeMediaSourceId: source.id
          }
        }
      }).then((stream) => {
        return stream
      }).catch((error) => {
        if (error.name === 'NotReadableError') {
          this.stopStream()
          this.screenActiveIndex = -1
          this.getScreensList()
        } else {
          console.log(error)
        }
      })
    },
    // 获取本程序窗口的镜像流数据
    getStreamSelf () {
      let source = this.screensList.find(item => item.name === document.title)
      return this.getStreamBySource(source)
    },
    // 启动webrtc websocket服务器
    startWebrtcServer () {
      this.$sharedObject('webrtcServer').start()
    },
    // 关闭webrtc websocket服务器
    closeWebrtcServer () {
      this.$sharedObject('webrtcServer').stop()
    },
    // 连接本地websocket服务器
    listenWebsocket () {
      this.wsWaiter = io.connect(`http://127.0.0.1:7600/servers`)
    },
    createSubWindow () {
      ipcRenderer.send('createSubWindow', {path: 'screenshare-image-client'})
    },
    sendStream () {
      clearInterval(this.wsTimer)
      this.wsTimer = setInterval(() => {
        let screenActive = this.screensList[this.screenActiveIndex]
        if (!screenActive) return
        this.getStreamBySource(screenActive).then((stream) => {
          this.takePhoto(stream).then((dataurl) => {
            this.imgSrc = dataurl
            this.wsWaiter && this.wsWaiter.emit('screenshot', dataurl)
          })
        })
      }, 2000)
    },
    stopStream () {
      clearInterval(this.wsTimer)
    },
    // 窗口Item被点击
    screenItemClick (index) {
      if (this.screenActiveIndex === index) return
      this.screenActiveIndex = index
    },
    // 拍照·方法1
    takePhoto (stream) {
      return new Promise((resolve, reject) => {
        if (!stream) {
          reject('error:没有视频流')
          return
        }
        let track = stream.getTracks()[0]
        if (!track) {
          reject('error:没有帧')
          return
        }
        let imageCapture = new ImageCapture(track)
        imageCapture.grabFrame().then((bitmap) => {
          let canvas = document.createElement('canvas')
          canvas.width = bitmap.width / 2
          canvas.height = bitmap.height / 2
          let context = canvas.getContext('2d')
          context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, canvas.width, canvas.height)
          resolve(canvas.toDataURL('image/jpeg', 70))
        }).catch((err) => {
          reject(err)
        })
      })
    },
    // 拍照·方法2 报错 Uncaught (in promise) DOMException: setOptions failed
    takePhoto2 (stream) {
      return new Promise((resolve, reject) => {
        if (!stream) {
          reject('error:没有视频流')
          return
        }
        let track = stream.getTracks()[0]
        if (!track) {
          reject('error:没有帧')
          return
        }
        let imageCapture = new ImageCapture(track)
        imageCapture.takePhoto().then((blob) => {
          let fileReader = new FileReader()
          fileReader.readAsDataURL(blob)
          fileReader.onloadend = (e) => {
            resolve(e.target.result)
          }
          fileReader.onerror = (err) => {
            reject(err)
          }
        })
      })
    },
  }
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
@gapSize: 10px;

.page-screenshare-image {
  display: flex;
  flex-direction: column;
  .page-body {
    height: 0;
    flex-grow: 1;
    fieldset {
      height: 100%;
      .fieldset-content {
        height: calc(100% - 2em);
        display: flex;
        flex-direction: column;
      }
      .screens-list {
        height: 0;
        flex-grow: 1;
        overflow-y: auto;
        .screen-item {
          margin-bottom: @gapSize;
          background-color: rgba(0,0,0,.1);
          img {
            display: block;
            width: 100%;
          }
          &.active {
            outline: 2px solid @colorWarning;
          }
        }
      }
      .x-button {
        margin-bottom: @gapSize;
      }
      img {
        width: 100%;
        height: 100%;
        object-fit: contain;
        background-color: #333;
      }
    }
  }
}
</style>
